package com.mi.global.shop.common.utils;

import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.graphics.Bitmap;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.webkit.URLUtil;

import com.facebook.binaryresource.BinaryResource;
import com.facebook.binaryresource.FileBinaryResource;
import com.facebook.cache.common.CacheKey;
import com.facebook.cache.disk.DiskCacheConfig;
import com.facebook.common.executors.CallerThreadExecutor;
import com.facebook.common.internal.Supplier;
import com.facebook.common.references.CloseableReference;
import com.facebook.datasource.BaseDataSubscriber;
import com.facebook.datasource.DataSource;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.backends.pipeline.PipelineDraweeController;
import com.facebook.drawee.controller.BaseControllerListener;
import com.facebook.drawee.generic.RoundingParams;
import com.facebook.drawee.view.SimpleDraweeView;
import com.facebook.imagepipeline.cache.DefaultCacheKeyFactory;
import com.facebook.imagepipeline.common.Priority;
import com.facebook.imagepipeline.common.ResizeOptions;
import com.facebook.imagepipeline.core.ImagePipeline;
import com.facebook.imagepipeline.core.ImagePipelineConfig;
import com.facebook.imagepipeline.core.ImagePipelineFactory;
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber;
import com.facebook.imagepipeline.image.CloseableImage;
import com.facebook.imagepipeline.request.BasePostprocessor;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;

import java.io.File;
import java.util.UUID;



/**
 * Created by lijiaxin on 2017/6/20 .
 */
public class FrescoUtils {

    /**
     * 缓存文件夹
     */
    public static String cacheFolderName = "imageCache";


    /**
     * 初始化操作，建议在子线程中进行
     * 添加的依赖：
     * compile 'com.facebook.fresco:fresco:0.10.0+'
     * compile 'com.facebook.fresco:animated-webp:0.10.0'
     * compile 'com.facebook.fresco:animated-gif:0.10.0'
     *
     * @param context
     * @param cacheSizeInM 磁盘缓存的大小，以M为单位
     */
    public static void init(final Context context, int cacheSizeInM) {

        DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder(context)
                .setMaxCacheSize(cacheSizeInM * 1024 * 1024)
                .setBaseDirectoryName(cacheFolderName)
                .setBaseDirectoryPathSupplier(new Supplier<File>() {
                    @Override
                    public File get() {
                        return context.getCacheDir();
                    }
                })
                .build();
        ImagePipelineConfig config = ImagePipelineConfig.newBuilder(context)
                .setMainDiskCacheConfig(diskCacheConfig)
                .setDownsampleEnabled(true)//配合ResizeOptions使用，它处理图片的速度比常规的裁剪更快，并且同时支持PNG，JPG以及WEP格式的图片
//                .setBitmapsConfig(Bitmap.Config.RGB_565)
                .build();
        Fresco.initialize(context, config);
    }


    /**
     * 加载网络图片
     * <p>
     * If the image has some ResizeOptions we put also the resized image into the cache with different key.
     * currently don't support downsampling / resizing for GIFs.
     *
     * @param url
     * @param drawView
     * @param processor
     * @param width
     * @param height
     * @param listener
     */
    public static void loadUrl(@NonNull String url, @NonNull SimpleDraweeView drawView, BasePostprocessor processor, int width, int height,
                               BaseControllerListener listener) {
        if (TextUtils.isEmpty(url)) return;
        load(Uri.parse(url), drawView, processor, width, height, listener);

    }
    public static void loadUrl(@NonNull Uri uri, @NonNull SimpleDraweeView drawView, BasePostprocessor processor, int width, int height,
                               BaseControllerListener listener) {

        load(uri, drawView, processor, width, height, listener);

    }

    /**
     * 　加载网络图片
     *
     * @param url
     * @param drawView
     */
    public static void loadUrl(@NonNull String url, @NonNull SimpleDraweeView drawView) {
        if (TextUtils.isEmpty(url)) return;
        load(Uri.parse(url), drawView, null, 0, 0, null);

    }
    public static void loadUrl(@NonNull Uri uri, @NonNull SimpleDraweeView drawView) {

        load(uri, drawView, null, 0, 0, null);

    }
    /**
     * 　加载网络圆圈图片
     *
     * @param url
     * @param drawView
     */
    public static void loadUrlAsCircle(@NonNull String url, @NonNull SimpleDraweeView drawView, int borderColor, int borderWidth) {
        if (TextUtils.isEmpty(url)) return;
        load(Uri.parse(url), drawView, null, 0, 0, null);
        setCircle(drawView,borderColor,borderWidth);

    }
    /**
     * 　加载本地File
     *
     * @param file
     * @param drawView
     * @param processor
     * @param width
     * @param height
     * @param listener
     */
    public static void loadFile(@NonNull String file, @NonNull SimpleDraweeView drawView, BasePostprocessor processor, int width, int height,
                                BaseControllerListener listener) {
        if (TextUtils.isEmpty(file)) return;
        load(getFileUri(file), drawView, processor, width, height, listener);

    }

    /**
     * 加载本地File
     *
     * @param file
     * @param drawView
     */
    public static void loadFile(@NonNull String file, @NonNull SimpleDraweeView drawView) {
        if (TextUtils.isEmpty(file)) return;
        load(getFileUri(file), drawView, null, 0, 0, null);

    }

    /**
     * 加载本地Res
     *
     * @param resId
     * @param drawView
     * @param processor
     * @param width
     * @param height
     * @param listener
     */
    public static void loadRes(int resId, @NonNull SimpleDraweeView drawView, BasePostprocessor processor, int width, int height,
                               BaseControllerListener listener) {

        load(getResUri(resId), drawView, processor, width, height, listener);

    }

    /**
     * 加载本地Res
     *
     * @param resId
     * @param drawView
     */
    public static void loadRes(int resId, @NonNull SimpleDraweeView drawView) {

        load(getResUri(resId), drawView, null, 0, 0, null);

    }

    public static void load(@NonNull Uri uri, @NonNull SimpleDraweeView drawView, BasePostprocessor processor, int width, int height,
                            BaseControllerListener listener) {
        if (uri == null) return;
        ResizeOptions resizeOptions = null;
        if (width > 0 && height > 0) {
            resizeOptions = new ResizeOptions(width, height);
        }
        ImageRequest request =
                ImageRequestBuilder.newBuilderWithSource(uri)
                        .setPostprocessor(processor)
                        .setResizeOptions(resizeOptions)
                        //缩放,在解码前修改内存中的图片大小, 配合Downsampling可以处理所有图片,否则只能处理jpg,
                        // 开启Downsampling:在初始化时设置.setDownsampleEnabled(true)
                        .setProgressiveRenderingEnabled(true)//支持图片渐进式加载
                        .setAutoRotateEnabled(true) //如果图片是侧着,可以自动旋转
                        .build();
        PipelineDraweeController controller =
                (PipelineDraweeController) Fresco.newDraweeControllerBuilder()
                        .setImageRequest(request)
                        .setControllerListener(listener)
                        .setOldController(drawView.getController())
                        .setAutoPlayAnimations(true) //自动播放gif动画
                        .build();


        drawView.setController(controller);
    }

    /**
     * 画圆图
     * @param drawView
     * @param borderColor
     * @param borderWidth
     */
    public static void setCircle(@NonNull SimpleDraweeView drawView, int borderColor, int borderWidth) {
        RoundingParams roundingParams = RoundingParams.asCircle();//这个方法在某些情况下无法成圆,比如gif
//        roundingParams.setOverlayColor(bgColor);//圆形遮罩的颜色,应该与背景色一致
        roundingParams.setBorderColor(borderColor);
        roundingParams.setBorderWidth(borderWidth);
        drawView.getHierarchy().setRoundingParams(roundingParams);

    }

    /**
     * 画圆角图
     *
     * @param drawView
     * @param cornersRadius
     * @param bgColor
     */
    public static void setCornersRadius(@NonNull SimpleDraweeView drawView, float cornersRadius, int bgColor) {
        RoundingParams roundingParams = RoundingParams.fromCornersRadius(cornersRadius);
        roundingParams.setOverlayColor(bgColor);
        drawView.getHierarchy().setRoundingParams(roundingParams);
    }

    /**
     * 暂停网络请求,可在快速滑动时使用
     */
    public static void pause() {
        Fresco.getImagePipeline().pause();
    }


    /**
     * 恢复网络请求，当滑动停止时使用
     */
    public static void resume() {
        Fresco.getImagePipeline().resume();

    }


    /**
     * 清除硬盘缓存
     */
    public static void clearDiskCache() {
        Fresco.getImagePipeline().clearDiskCaches();

    }
    /**
     * 清除内存缓存
     */
    public static void clearMemoryCache() {
        Fresco.getImagePipeline().clearMemoryCaches();

    }

    /**
     * 清楚被标记的缓存
     * @param level
     */
    public static void TrimMemory(int level) {
        try {
            if (level >= ComponentCallbacks2.TRIM_MEMORY_MODERATE) { // 60
                ImagePipelineFactory.getInstance().getImagePipeline().clearMemoryCaches();
            }
        } catch (Exception e) {

        }
    }
    /**
     * 清除单张图片缓存
     *
     * @param url
     */
    public static void clearCacheByUrl(String url) {
        if (TextUtils.isEmpty(url)) return;
        ImagePipeline imagePipeline = Fresco.getImagePipeline();
        Uri uri = Uri.parse(url);
        imagePipeline.evictFromDiskCache(uri);
    }

    /**
     * 从fresco的本地缓存拿到图片,注意文件的结束符并不是常见的.jpg,.png等，如果需要另存，可自行另存
     *
     * @param url
     */
    public static File getFileFromDiskCache(String url) {
        File localFile = null;
        if (!TextUtils.isEmpty(url)) {
            CacheKey cacheKey = DefaultCacheKeyFactory.getInstance().getEncodedCacheKey(ImageRequest.fromUri(url), null);
            if (ImagePipelineFactory.getInstance().getMainFileCache().hasKey(cacheKey)) {
                BinaryResource resource = ImagePipelineFactory.getInstance().getMainFileCache().getResource(cacheKey);
                localFile = ((FileBinaryResource) resource).getFile();
            } else if (ImagePipelineFactory.getInstance().getSmallImageFileCache().hasKey(cacheKey)) {
                BinaryResource resource = ImagePipelineFactory.getInstance().getSmallImageFileCache().getResource(cacheKey);
                localFile = ((FileBinaryResource) resource).getFile();
            }
        }
        return localFile;
    }

    /**
     * 拷贝缓存文件,指定目标路径和文件名
     *
     * @param url
     * @param dir
     * @param fileName
     * @return
     */
    public static boolean copyCacheFile(String url, File dir, String fileName) {
        File path = new File(dir, fileName);
        return copyCacheFile(url, path);
    }

    /**
     * 拷贝到某一个文件,已指定文件名
     *
     * @param url  图片的完整url
     * @param path 目标文件路径
     * @return
     */
    public static boolean copyCacheFile(String url, File path) {
        if (path == null) {
            return false;
        }
        File file = getFileFromDiskCache(url);
        if (file == null) {
            return false;
        }

        if (path.isDirectory()) {
            throw new RuntimeException(path + "is a directory,you should call copyCacheFileToDir(String url,File dir)");
        }
        boolean isSuccess = file.renameTo(path);

        return isSuccess;
    }


    /**
     * this method is return very fast, you can use it in UI thread.
     *
     * @param url
     * @return 该url对应的图片是否已经缓存到本地
     */
    public static boolean isCached(String url) {

        // return Fresco.getImagePipeline().isInDiskCache(Uri.parse(url));

        if (TextUtils.isEmpty(url)) {
            return false;
        }

        DataSource<Boolean> isIn = Fresco.getImagePipeline().isInDiskCache(Uri.parse(url));
        if (isIn != null) {
            try {
                return isIn.getResult();
            } catch (Exception e) {
                return false;
            }
        } else {
            return false;
        }
    }


    /**
     * 文件下载到文件夹中：将图片缓存到本地后，将缓存的图片文件copy到另一个文件夹中
     * <p>
     * 容易发生如下异常，progress在100处停留时间长
     * dalvikvm: Could not find method android.graphics.Bitmap.getAllocationByteCount,
     * referenced from method com.facebook.imageutils.BitmapUtil.getSizeInBytes
     * 06-21 16:15:39.547 3043-3244/com.hss01248.tools W/dalvikvm: VFY:
     * unable to resolve virtual method 569: Landroid/graphics/Bitmap;.getAllocationByteCount ()I
     *
     * @param url
     * @param context
     * @param dir      保存图片的文件夹
     * @param listener 自己定义的回调
     */
    public static void download(final String url, Context context, final File dir, final DownloadListener listener) {
        if (TextUtils.isEmpty(url)) return;
        ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
                .build();
        final ImagePipeline imagePipeline = Fresco.getImagePipeline();


        DataSource<Void> dataSource = imagePipeline.prefetchToDiskCache(imageRequest, context, Priority.HIGH);
        dataSource.subscribe(new BaseDataSubscriber<Void>() {
            @Override
            protected void onNewResultImpl(DataSource<Void> dataSource) {


                File file = copyCacheFileToDir(url, dir);
                clearCacheByUrl(url);//清除缓存
                if (listener == null) return;
                if (file == null || !file.exists()) {
                    listener.onFail();
                } else {
                    listener.onSuccess(file);
                }

            }

            @Override
            public void onProgressUpdate(DataSource<Void> dataSource) {
                super.onProgressUpdate(dataSource);
                if (listener != null)
                    listener.onProgress(dataSource.getProgress());
            }

            @Override
            protected void onFailureImpl(DataSource<Void> dataSource) {
                if (listener != null)
                    listener.onFail();
            }
        }, CallerThreadExecutor.getInstance());


    }

    /**
     * 拷贝到某一个目录中,自动命名
     *
     * @param url
     * @param dir
     * @return
     */
    public static File copyCacheFileToDir(String url, File dir) {

        if (dir == null) {
            return null;
        }
        if (!dir.isDirectory()) {
            throw new RuntimeException(dir + "is not a directory,you should call copyCacheFile(String url,File path)");
        }
        if (!dir.exists()) {
            dir.mkdirs();
        }
        String fileName = URLUtil.guessFileName(url, "", "");//android SDK 提供的方法.
        // 注意不能直接采用file的getName拿到文件名,因为缓存文件是用cacheKey命名的
        if (TextUtils.isEmpty(fileName)) {
            fileName = UUID.randomUUID().toString();
        }
        File newFile = new File(dir, fileName);

        boolean isSuccess = copyCacheFile(url, newFile);
        if (isSuccess) {
            return newFile;
        } else {
            return null;
        }

    }

    /**
     * 拿到指定宽高的bitmap
     *
     * @param url
     * @param context
     * @param width
     * @param height
     * @param listener
     */
    public static void getBitmap(String url, Context context, int width, int height, final BitmapListener listener) {
        getBitmapWithProcessor(url, context, width, height, null, listener);
    }

    public static void getBitmap(String url, Context context, BitmapListener listener) {
        getBitmapWithProcessor(url, context, 0, 0, null, listener);
    }


    /**
     * 拿到指定宽高，并经过Processor处理的bitmap
     *
     * @param url
     * @param context
     * @param width
     * @param height
     * @param processor 后处理器,可为null
     * @param listener
     */
    private static void getBitmapWithProcessor(final String url, Context context, final int width, final int height,
                                               BasePostprocessor processor, final BitmapListener listener) {
        if (TextUtils.isEmpty(url)) return;
        ResizeOptions resizeOptions = null;
        if (width != 0 && height != 0) {
            resizeOptions = new ResizeOptions(width, height);
        }

        ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url))
                .setProgressiveRenderingEnabled(false) //我们是拿bitmap对象,不是显示,所以这里不需要渐进渲染
                .setPostprocessor(processor)
                .setResizeOptions(resizeOptions)//无法支持gif
                .build();

        ImagePipeline imagePipeline = Fresco.getImagePipeline();

        DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, context);
        dataSource.subscribe(new BaseBitmapDataSubscriber() {
            @Override
            protected void onNewResultImpl(Bitmap bitmap) {
                //注意，gif图片解码方法与普通图片不一样，是无法拿到bitmap的。如果要把gif的第一帧的bitmap返回，怎么做？
                //GifImage.create(bytes).decode(1l,9).getFrameInfo(1).
                if (url.contains("gif")) {
                    File cacheFile = getFileFromDiskCache(url);
                    if (cacheFile.exists()) {
                        Bitmap bitmapGif = GifUtils.getBitmapFromGifFile(cacheFile);//拿到gif第一帧的bitmap
                        Bitmap target;
                        if (width == 0 || height == 0) {
                            target = bitmapGif;
                        } else {
                            target = BitmapUtils.compressBitmap(bitmapGif, true, width, height);//将bitmap压缩到指定宽高。
                        }
                        if (target != null && listener != null) {
                            listener.onSuccess(target);
                        } else if (listener != null) {
                            listener.onFail();
                        }

                    } else if (listener != null) {
                        listener.onFail();
                    }

                } else if (listener != null) {
                    listener.onSuccess(bitmap);
                }

            }

            @Override
            protected void onFailureImpl(DataSource<CloseableReference<CloseableImage>> dataSource) {
                if (listener != null)
                    listener.onFail();
            }
        }, CallerThreadExecutor.getInstance());

    }


    public static Uri getFileUri(File file) {
        return Uri.fromFile(file);
    }

    public static Uri getFileUri(String filePath) {
        return Uri.fromFile(new File(filePath));
    }

    public static Uri getResUri(int resId) {
        return Uri.parse("res://xxyy/" + resId);
    }


    public interface BitmapListener {
        void onSuccess(Bitmap bitmap);

        void onFail();
    }

    public interface DownloadListener {
        void onSuccess(File file);

        void onFail();

        void onProgress(float progress);
    }
}
